import logging

from copy import copy

from util import *

def isTreeExpandable(tree):
  lex, dyn, code=tree

  ftype=code[0]
  if ftype=='literal' or ftype=='symref' or ftype=='symdef' or ftype=='block':
    return False
  elif ftype=='func':
    if checkResolved(tree):
      return True
    else:
      fargs=code[1][1]

      for arg in fargs:
        if isTreeExpandable(arg):
          return True
  elif ftype=='native':
    if checkResolved(tree):
      return False
    else:
      fargs=code[1][1]

      for arg in fargs:
        if isTreeExpandable(arg):
          return True
  else:
    print('Unsupported expansion type!: '+str(tree))

  return False

def expandTree(system, userlib, tree):
  return expandBranch(system, userlib, tree)

def expandBranch(system, userlib, branch):
  lex, dyn, code=branch

  ftype=code[0]
  if ftype=='literal' or ftype=='block':
    return branch
  elif ftype=='symref':
    varName=code[1]
    return (lex, dyn, lookup(system, userlib, lex, dyn, varName))
  elif ftype=='func' or ftype=='native':
    if ftype=='func':
      branch=expandBranchFunction(system, userlib, branch)

    lex, dyn, code=branch
    ftype=code[0]
    fname=code[1][0]
    fargs=code[1][1]

    args=copy(fargs)
    for x in range(len(args)):
      arg=args[x]
      if type(arg)!=tuple:
        arg=(lex, dyn, arg)
        args[x]=arg
        code=[ftype, [fname, args]]
        branch=(lex, dyn, code)

    for x in range(len(args)):
      arg=args[x]
      if isTreeExpandable(arg):
        args[x]=expandBranch(system, userlib, arg)
        code=[ftype, [fname, args]]
        branch=(lex, dyn, code)
  else:
    print('Unsupported arg!: '+str(branch))

  return branch

def expandBranchFunction(system, userlib, branch):
  lex=branch[0]
  dyn=branch[1]
  code=branch[2]

  ftype=code[0]
  fname=code[1][0]
  fargs=code[1][1]

  if ftype=='func':
    f=lookupFunction(system, userlib, lex, dyn, fname, fargs)
    if not f:
      print('No such function '+fname)
      print(fname in lex)
      print(fname in dyn)
      return

    if type(f)==tuple:
      lex, dyn, f=f

    if type(f)==list and f[0]=='block':
      f=f[1]

    if f['type']=='method':
      params=f['params']
      if len(params)!=len(fargs):
        print('Type error, length mismatch: '+str(params)+' '+str(fargs))
      flex=copy(lex)
      fdyn=copy(dyn)

      for x in range(len(params)):
        param=params[x]
        fdyn[param]=fargs[x]
      subbranch=tuplifyTree(flex, fdyn, f['code'])
    elif f['type']=='native':
      flex=copy(lex)
      fdyn=copy(dyn)
      args=copy(fargs)
      fcode=f['code']
      for x in range(len(args)):
        args[x]=tuplifyTree(flex, fdyn, args[x])
      subbranch=(lex, dyn, ['native', [fcode, args]])

    return subbranch
  else:
    print('Error! Not a function!')
